/*
 * ! JSON v3.2.6 | http://bestiejs.github.io/json3 | Copyright 2012-2013, Kit
 * Cambridge | http://kit.mit-license.org
 */
;
(function(window) {
	// Convenience aliases.
	var getClass = {}.toString, isProperty, forEach, undef;

	// Detect the `define` function exposed by asynchronous module loaders. The
	// strict `define` check is necessary for compatibility with `r.js`.
	var isLoader = typeof define === "function" && define.amd;

	// Detect native implementations.
	var nativeJSON = typeof JSON == "object" && JSON;

	// Set up the JSON 3 namespace, preferring the CommonJS `exports` object if
	// available.
	var JSON3 = typeof exports == "object" && exports && !exports.nodeType
			&& exports;

	if (JSON3 && nativeJSON) {
		// Explicitly delegate to the native `stringify` and `parse`
		// implementations in CommonJS environments.
		JSON3.stringify = nativeJSON.stringify;
		JSON3.parse = nativeJSON.parse;
	} else {
		// Export for web browsers, JavaScript engines, and asynchronous module
		// loaders, using the global `JSON` object if available.
		JSON3 = window.JSON = nativeJSON || {};
	}

	// Test the `Date#getUTC*` methods. Based on work by @Yaffle.
	var isExtended = new Date(-3509827334573292);
	try {
		// The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical
		// results for certain dates in Opera >= 10.53.
		isExtended = isExtended.getUTCFullYear() == -109252
				&& isExtended.getUTCMonth() === 0
				&& isExtended.getUTCDate() === 1
				&&
				// Safari < 2.0.2 stores the internal millisecond time value
				// correctly,
				// but clips the values returned by the date methods to the
				// range of
				// signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]).
				isExtended.getUTCHours() == 10
				&& isExtended.getUTCMinutes() == 37
				&& isExtended.getUTCSeconds() == 6
				&& isExtended.getUTCMilliseconds() == 708;
	} catch (exception) {
	}

	// Internal: Determines whether the native `JSON.stringify` and `parse`
	// implementations are spec-compliant. Based on work by Ken Snyder.
	function has(name) {
		if (has[name] !== undef) {
			// Return cached feature test result.
			return has[name];
		}

		var isSupported;
		if (name == "bug-string-char-index") {
			// IE <= 7 doesn't support accessing string characters using square
			// bracket notation. IE 8 only supports this for primitives.
			isSupported = "a"[0] != "a";
		} else if (name == "json") {
			// Indicates whether both `JSON.stringify` and `JSON.parse` are
			// supported.
			isSupported = has("json-stringify") && has("json-parse");
		} else {
			var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';
			// Test `JSON.stringify`.
			if (name == "json-stringify") {
				var stringify = JSON3.stringify, stringifySupported = typeof stringify == "function"
						&& isExtended;
				if (stringifySupported) {
					// A test function object with a custom `toJSON` method.
					(value = function() {
						return 1;
					}).toJSON = value;
					try {
						stringifySupported =
						// Firefox 3.1b1 and b2 serialize string, number, and
						// boolean
						// primitives as object literals.
						stringify(0) === "0"
								&&
								// FF 3.1b1, b2, and JSON 2 serialize wrapped
								// primitives as object
								// literals.
								stringify(new Number()) === "0"
								&& stringify(new String()) == '""'
								&&
								// FF 3.1b1, 2 throw an error if the value is
								// `null`, `undefined`, or
								// does not define a canonical JSON
								// representation (this applies to
								// objects with `toJSON` properties as well,
								// *unless* they are nested
								// within an object or array).
								stringify(getClass) === undef
								&&
								// IE 8 serializes `undefined` as `"undefined"`.
								// Safari <= 5.1.7 and
								// FF 3.1b3 pass this test.
								stringify(undef) === undef
								&&
								// Safari <= 5.1.7 and FF 3.1b3 throw `Error`s
								// and `TypeError`s,
								// respectively, if the value is omitted
								// entirely.
								stringify() === undef
								&&
								// FF 3.1b1, 2 throw an error if the given value
								// is not a number,
								// string, array, object, Boolean, or `null`
								// literal. This applies to
								// objects with custom `toJSON` methods as well,
								// unless they are nested
								// inside object or array literals. YUI 3.0.0b1
								// ignores custom `toJSON`
								// methods entirely.
								stringify(value) === "1"
								&& stringify([value]) == "[1]"
								&&
								// Prototype <= 1.6.1 serializes `[undefined]`
								// as `"[]"` instead of
								// `"[null]"`.
								stringify([undef]) == "[null]"
								&&
								// YUI 3.0.0b1 fails to serialize `null`
								// literals.
								stringify(null) == "null"
								&&
								// FF 3.1b1, 2 halts serialization if an array
								// contains a function:
								// `[1, true, getClass, 1]` serializes as
								// "[1,true,],". FF 3.1b3
								// elides non-JSON values from objects and
								// arrays, unless they
								// define custom `toJSON` methods.
								stringify([undef, getClass, null]) == "[null,null,null]"
								&&
								// Simple serialization test. FF 3.1b1 uses
								// Unicode escape sequences
								// where character escape codes are expected
								// (e.g., `\b` => `\u0008`).
								stringify({
											"a" : [value, true, false, null,
													"\x00\b\n\f\r\t"]
										}) == serialized
								&&
								// FF 3.1b1 and b2 ignore the `filter` and
								// `width` arguments.
								stringify(null, value) === "1"
								&& stringify([1, 2], null, 1) == "[\n 1,\n 2\n]"
								&&
								// JSON 2, Prototype <= 1.7, and older WebKit
								// builds incorrectly
								// serialize extended years.
								stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"'
								&&
								// The milliseconds are optional in ES 5, but
								// required in 5.1.
								stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"'
								&&
								// Firefox <= 11.0 incorrectly serializes years
								// prior to 0 as negative
								// four-digit years instead of six-digit years.
								// Credits: @Yaffle.
								stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"'
								&&
								// Safari <= 5.1.5 and Opera >= 10.53
								// incorrectly serialize millisecond
								// values less than 1000. Credits: @Yaffle.
								stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"';
					} catch (exception) {
						stringifySupported = false;
					}
				}
				isSupported = stringifySupported;
			}
			// Test `JSON.parse`.
			if (name == "json-parse") {
				var parse = JSON3.parse;
				if (typeof parse == "function") {
					try {
						// FF 3.1b1, b2 will throw an exception if a bare
						// literal is provided.
						// Conforming implementations should also coerce the
						// initial argument to
						// a string prior to parsing.
						if (parse("0") === 0 && !parse(false)) {
							// Simple parsing test.
							value = parse(serialized);
							var parseSupported = value["a"].length == 5
									&& value["a"][0] === 1;
							if (parseSupported) {
								try {
									// Safari <= 5.1.2 and FF 3.1b1 allow
									// unescaped tabs in strings.
									parseSupported = !parse('"\t"');
								} catch (exception) {
								}
								if (parseSupported) {
									try {
										// FF 4.0 and 4.0.1 allow leading `+`
										// signs and leading
										// decimal points. FF 4.0, 4.0.1, and IE
										// 9-10 also allow
										// certain octal literals.
										parseSupported = parse("01") !== 1;
									} catch (exception) {
									}
								}
								if (parseSupported) {
									try {
										// FF 4.0, 4.0.1, and Rhino 1.7R3-R4
										// allow trailing decimal
										// points. These environments, along
										// with FF 3.1b1 and 2,
										// also allow trailing commas in JSON
										// objects and arrays.
										parseSupported = parse("1.") !== 1;
									} catch (exception) {
									}
								}
							}
						}
					} catch (exception) {
						parseSupported = false;
					}
				}
				isSupported = parseSupported;
			}
		}
		return has[name] = !!isSupported;
	}

	if (!has("json")) {
		// Common `[[Class]]` name aliases.
		var functionClass = "[object Function]";
		var dateClass = "[object Date]";
		var numberClass = "[object Number]";
		var stringClass = "[object String]";
		var arrayClass = "[object Array]";
		var booleanClass = "[object Boolean]";

		// Detect incomplete support for accessing string characters by index.
		var charIndexBuggy = has("bug-string-char-index");

		// Define additional utility methods if the `Date` methods are buggy.
		if (!isExtended) {
			var floor = Math.floor;
			// A mapping between the months of the year and the number of days
			// between
			// January 1st and the first of the respective month.
			var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
			// Internal: Calculates the number of days between the Unix epoch
			// and the
			// first day of the given month.
			var getDay = function(year, month) {
				return Months[month] + 365 * (year - 1970)
						+ floor((year - 1969 + (month = +(month > 1))) / 4)
						- floor((year - 1901 + month) / 100)
						+ floor((year - 1601 + month) / 400);
			};
		}

		// Internal: Determines if a property is a direct property of the given
		// object. Delegates to the native `Object#hasOwnProperty` method.
		if (!(isProperty = {}.hasOwnProperty)) {
			isProperty = function(property) {
				var members = {}, constructor;
				if ((members.__proto__ = null, members.__proto__ = {
					// The *proto* property cannot be set multiple times in
					// recent
					// versions of Firefox and SeaMonkey.
					"toString" : 1
				}, members).toString != getClass) {
					// Safari <= 2.0.3 doesn't implement
					// `Object#hasOwnProperty`, but
					// supports the mutable *proto* property.
					isProperty = function(property) {
						// Capture and break the object's prototype chain (see
						// section 8.6.2
						// of the ES 5.1 spec). The parenthesized expression
						// prevents an
						// unsafe transformation by the Closure Compiler.
						var original = this.__proto__, result = property in (this.__proto__ = null, this);
						// Restore the original prototype chain.
						this.__proto__ = original;
						return result;
					};
				} else {
					// Capture a reference to the top-level `Object`
					// constructor.
					constructor = members.constructor;
					// Use the `constructor` property to simulate
					// `Object#hasOwnProperty` in
					// other environments.
					isProperty = function(property) {
						var parent = (this.constructor || constructor).prototype;
						return property in this
								&& !(property in parent && this[property] === parent[property]);
					};
				}
				members = null;
				return isProperty.call(this, property);
			};
		}

		// Internal: A set of primitive types used by `isHostType`.
		var PrimitiveTypes = {
			'boolean' : 1,
			'number' : 1,
			'string' : 1,
			'undefined' : 1
		};

		// Internal: Determines if the given object `property` value is a
		// non-primitive.
		var isHostType = function(object, property) {
			var type = typeof object[property];
			return type == 'object'
					? !!object[property]
					: !PrimitiveTypes[type];
		};

		// Internal: Normalizes the `for...in` iteration algorithm across
		// environments. Each enumerated key is yielded to a `callback`
		// function.
		forEach = function(object, callback) {
			var size = 0, Properties, members, property;

			// Tests for bugs in the current environment's `for...in` algorithm.
			// The
			// `valueOf` property inherits the non-enumerable flag from
			// `Object.prototype` in older versions of IE, Netscape, and
			// Mozilla.
			(Properties = function() {
				this.valueOf = 0;
			}).prototype.valueOf = 0;

			// Iterate over a new instance of the `Properties` class.
			members = new Properties();
			for (property in members) {
				// Ignore all properties inherited from `Object.prototype`.
				if (isProperty.call(members, property)) {
					size++;
				}
			}
			Properties = members = null;

			// Normalize the iteration algorithm.
			if (!size) {
				// A list of non-enumerable properties inherited from
				// `Object.prototype`.
				members = ["valueOf", "toString", "toLocaleString",
						"propertyIsEnumerable", "isPrototypeOf",
						"hasOwnProperty", "constructor"];
				// IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed
				// non-enumerable
				// properties.
				forEach = function(object, callback) {
					var isFunction = getClass.call(object) == functionClass, property, length;
					var hasProperty = !isFunction
							&& typeof object.constructor != 'function'
							&& isHostType(object, 'hasOwnProperty')
							? object.hasOwnProperty
							: isProperty;
					for (property in object) {
						// Gecko <= 1.0 enumerates the `prototype` property of
						// functions under
						// certain conditions; IE does not.
						if (!(isFunction && property == "prototype")
								&& hasProperty.call(object, property)) {
							callback(property);
						}
					}
					// Manually invoke the callback for each non-enumerable
					// property.
					for (length = members.length; property = members[--length]; hasProperty
							.call(object, property)
							&& callback(property));
				};
			} else if (size == 2) {
				// Safari <= 2.0.4 enumerates shadowed properties twice.
				forEach = function(object, callback) {
					// Create a set of iterated properties.
					var members = {}, isFunction = getClass.call(object) == functionClass, property;
					for (property in object) {
						// Store each property name to prevent double
						// enumeration. The
						// `prototype` property of functions is not enumerated
						// due to cross-
						// environment inconsistencies.
						if (!(isFunction && property == "prototype")
								&& !isProperty.call(members, property)
								&& (members[property] = 1)
								&& isProperty.call(object, property)) {
							callback(property);
						}
					}
				};
			} else {
				// No bugs detected; use the standard `for...in` algorithm.
				forEach = function(object, callback) {
					var isFunction = getClass.call(object) == functionClass, property, isConstructor;
					for (property in object) {
						if (!(isFunction && property == "prototype")
								&& isProperty.call(object, property)
								&& !(isConstructor = property === "constructor")) {
							callback(property);
						}
					}
					// Manually invoke the callback for the `constructor`
					// property due to
					// cross-environment inconsistencies.
					if (isConstructor
							|| isProperty.call(object,
									(property = "constructor"))) {
						callback(property);
					}
				};
			}
			return forEach(object, callback);
		};

		// Public: Serializes a JavaScript `value` as a JSON string. The
		// optional
		// `filter` argument may specify either a function that alters how
		// object and
		// array members are serialized, or an array of strings and numbers that
		// indicates which properties should be serialized. The optional `width`
		// argument may be either a string or number that specifies the
		// indentation
		// level of the output.
		if (!has("json-stringify")) {
			// Internal: A map of control characters and their escaped
			// equivalents.
			var Escapes = {
				92 : "\\\\",
				34 : '\\"',
				8 : "\\b",
				12 : "\\f",
				10 : "\\n",
				13 : "\\r",
				9 : "\\t"
			};

			// Internal: Converts `value` into a zero-padded string such that
			// its
			// length is at least equal to `width`. The `width` must be <= 6.
			var leadingZeroes = "000000";
			var toPaddedString = function(width, value) {
				// The `|| 0` expression is necessary to work around a bug in
				// Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`.
				return (leadingZeroes + (value || 0)).slice(-width);
			};

			// Internal: Double-quotes a string `value`, replacing all ASCII
			// control
			// characters (characters with code unit values between 0 and 31)
			// with
			// their escaped equivalents. This is an implementation of the
			// `Quote(value)` operation defined in ES 5.1 section 15.12.3.
			var unicodePrefix = "\\u00";
			var quote = function(value) {
				var result = '"', index = 0, length = value.length, isLarge = length > 10
						&& charIndexBuggy, symbols;
				if (isLarge) {
					symbols = value.split("");
				}
				for (; index < length; index++) {
					var charCode = value.charCodeAt(index);
					// If the character is a control character, append its
					// Unicode or
					// shorthand escape sequence; otherwise, append the
					// character as-is.
					switch (charCode) {
						case 8 :
						case 9 :
						case 10 :
						case 12 :
						case 13 :
						case 34 :
						case 92 :
							result += Escapes[charCode];
							break;
						default :
							if (charCode < 32) {
								result += unicodePrefix
										+ toPaddedString(2, charCode
														.toString(16));
								break;
							}
							result += isLarge ? symbols[index] : charIndexBuggy
									? value.charAt(index)
									: value[index];
					}
				}
				return result + '"';
			};

			// Internal: Recursively serializes an object. Implements the
			// `Str(key, holder)`, `JO(value)`, and `JA(value)` operations.
			var serialize = function(property, object, callback, properties,
					whitespace, indentation, stack) {
				var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result;
				try {
					// Necessary for host object support.
					value = object[property];
				} catch (exception) {
				}
				if (typeof value == "object" && value) {
					className = getClass.call(value);
					if (className == dateClass
							&& !isProperty.call(value, "toJSON")) {
						if (value > -1 / 0 && value < 1 / 0) {
							// Dates are serialized according to the
							// `Date#toJSON` method
							// specified in ES 5.1 section 15.9.5.44. See
							// section 15.9.1.15
							// for the ISO 8601 date time string format.
							if (getDay) {
								// Manually compute the year, month, date,
								// hours, minutes,
								// seconds, and milliseconds if the `getUTC*`
								// methods are
								// buggy. Adapted from @Yaffle's `date-shim`
								// project.
								date = floor(value / 864e5);
								for (year = floor(date / 365.2425) + 1970 - 1; getDay(
										year + 1, 0) <= date; year++);
								for (month = floor((date - getDay(year, 0))
										/ 30.42); getDay(year, month + 1) <= date; month++);
								date = 1 + date - getDay(year, month);
								// The `time` value specifies the time within
								// the day (see ES
								// 5.1 section 15.9.1.2). The formula `(A % B +
								// B) % B` is used
								// to compute `A modulo B`, as the `%` operator
								// does not
								// correspond to the `modulo` operation for
								// negative numbers.
								time = (value % 864e5 + 864e5) % 864e5;
								// The hours, minutes, seconds, and milliseconds
								// are obtained by
								// decomposing the time within the day. See
								// section 15.9.1.10.
								hours = floor(time / 36e5) % 24;
								minutes = floor(time / 6e4) % 60;
								seconds = floor(time / 1e3) % 60;
								milliseconds = time % 1e3;
							} else {
								year = value.getUTCFullYear();
								month = value.getUTCMonth();
								date = value.getUTCDate();
								hours = value.getUTCHours();
								minutes = value.getUTCMinutes();
								seconds = value.getUTCSeconds();
								milliseconds = value.getUTCMilliseconds();
							}
							// Serialize extended years correctly.
							value = (year <= 0 || year >= 1e4
									? (year < 0 ? "-" : "+")
											+ toPaddedString(6, year < 0
															? -year
															: year)
									: toPaddedString(4, year))
									+ "-"
									+ toPaddedString(2, month + 1)
									+ "-"
									+ toPaddedString(2, date)
									+
									// Months, dates, hours, minutes, and
									// seconds should have two
									// digits; milliseconds should have three.
									"T"
									+ toPaddedString(2, hours)
									+ ":"
									+ toPaddedString(2, minutes)
									+ ":"
									+ toPaddedString(2, seconds) +
									// Milliseconds are optional in ES 5.0, but
									// required in 5.1.
									"." + toPaddedString(3, milliseconds) + "Z";
						} else {
							value = null;
						}
					} else if (typeof value.toJSON == "function"
							&& ((className != numberClass
									&& className != stringClass && className != arrayClass) || isProperty
									.call(value, "toJSON"))) {
						// Prototype <= 1.6.1 adds non-standard `toJSON` methods
						// to the
						// `Number`, `String`, `Date`, and `Array` prototypes.
						// JSON 3
						// ignores all `toJSON` methods on these objects unless
						// they are
						// defined directly on an instance.
						value = value.toJSON(property);
					}
				}
				if (callback) {
					// If a replacement function was provided, call it to obtain
					// the value
					// for serialization.
					value = callback.call(object, property, value);
				}
				if (value === null) {
					return "null";
				}
				className = getClass.call(value);
				if (className == booleanClass) {
					// Booleans are represented literally.
					return "" + value;
				} else if (className == numberClass) {
					// JSON numbers must be finite. `Infinity` and `NaN` are
					// serialized as
					// `"null"`.
					return value > -1 / 0 && value < 1 / 0
							? "" + value
							: "null";
				} else if (className == stringClass) {
					// Strings are double-quoted and escaped.
					return quote("" + value);
				}
				// Recursively serialize objects and arrays.
				if (typeof value == "object") {
					// Check for cyclic structures. This is a linear search;
					// performance
					// is inversely proportional to the number of unique nested
					// objects.
					for (length = stack.length; length--;) {
						if (stack[length] === value) {
							// Cyclic structures cannot be serialized by
							// `JSON.stringify`.
							throw TypeError();
						}
					}
					// Add the object to the stack of traversed objects.
					stack.push(value);
					results = [];
					// Save the current indentation level and indent one
					// additional level.
					prefix = indentation;
					indentation += whitespace;
					if (className == arrayClass) {
						// Recursively serialize array elements.
						for (index = 0, length = value.length; index < length; index++) {
							element = serialize(index, value, callback,
									properties, whitespace, indentation, stack);
							results.push(element === undef ? "null" : element);
						}
						result = results.length ? (whitespace
								? "[\n" + indentation
										+ results.join(",\n" + indentation)
										+ "\n" + prefix + "]"
								: ("[" + results.join(",") + "]")) : "[]";
					} else {
						// Recursively serialize object members. Members are
						// selected from
						// either a user-specified list of property names, or
						// the object
						// itself.
						forEach(properties || value, function(property) {
							var element = serialize(property, value, callback,
									properties, whitespace, indentation, stack);
							if (element !== undef) {
								// According to ES 5.1 section 15.12.3: "If
								// `gap` {whitespace}
								// is not the empty string, let `member`
								// {quote(property) + ":"}
								// be the concatenation of `member` and the
								// `space` character."
								// The "`space` character" refers to the literal
								// space
								// character, not the `space` {width} argument
								// provided to
								// `JSON.stringify`.
								results.push(quote(property) + ":"
										+ (whitespace ? " " : "") + element);
							}
						});
						result = results.length ? (whitespace
								? "{\n" + indentation
										+ results.join(",\n" + indentation)
										+ "\n" + prefix + "}"
								: ("{" + results.join(",") + "}")) : "{}";
					}
					// Remove the object from the traversed object stack.
					stack.pop();
					return result;
				}
			};

			// Public: `JSON.stringify`. See ES 5.1 section 15.12.3.
			JSON3.stringify = function(source, filter, width) {
				var whitespace, callback, properties, className;
				if (typeof filter == "function" || typeof filter == "object"
						&& filter) {
					if ((className = getClass.call(filter)) == functionClass) {
						callback = filter;
					} else if (className == arrayClass) {
						// Convert the property names array into a makeshift
						// set.
						properties = {};
						for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass
								.call(value)), className == stringClass
								|| className == numberClass)
								&& (properties[value] = 1));
					}
				}
				if (width) {
					if ((className = getClass.call(width)) == numberClass) {
						// Convert the `width` to an integer and create a string
						// containing
						// `width` number of space characters.
						if ((width -= width % 1) > 0) {
							for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " ");
						}
					} else if (className == stringClass) {
						whitespace = width.length <= 10 ? width : width.slice(
								0, 10);
					}
				}
				// Opera <= 7.54u2 discards the values associated with empty
				// string keys
				// (`""`) only if they are used directly within an object member
				// list
				// (e.g., `!("" in { "": 1})`).
				return serialize("", (value = {}, value[""] = source, value),
						callback, properties, whitespace, "", []);
			};
		}

		// Public: Parses a JSON source string.
		if (!has("json-parse")) {
			var fromCharCode = String.fromCharCode;

			// Internal: A map of escaped control characters and their unescaped
			// equivalents.
			var Unescapes = {
				92 : "\\",
				34 : '"',
				47 : "/",
				98 : "\b",
				116 : "\t",
				110 : "\n",
				102 : "\f",
				114 : "\r"
			};

			// Internal: Stores the parser state.
			var Index, Source;

			// Internal: Resets the parser state and throws a `SyntaxError`.
			var abort = function() {
				Index = Source = null;
				throw SyntaxError();
			};

			// Internal: Returns the next token, or `"$"` if the parser has
			// reached
			// the end of the source string. A token may be a string, number,
			// `null`
			// literal, or Boolean literal.
			var lex = function() {
				var source = Source, length = source.length, value, begin, position, isSigned, charCode;
				while (Index < length) {
					charCode = source.charCodeAt(Index);
					switch (charCode) {
						case 9 :
						case 10 :
						case 13 :
						case 32 :
							// Skip whitespace tokens, including tabs, carriage
							// returns, line
							// feeds, and space characters.
							Index++;
							break;
						case 123 :
						case 125 :
						case 91 :
						case 93 :
						case 58 :
						case 44 :
							// Parse a punctuator token (`{`, `}`, `[`, `]`,
							// `:`, or `,`) at
							// the current position.
							value = charIndexBuggy
									? source.charAt(Index)
									: source[Index];
							Index++;
							return value;
						case 34 :
							// `"` delimits a JSON string; advance to the next
							// character and
							// begin parsing the string. String tokens are
							// prefixed with the
							// sentinel `@` character to distinguish them from
							// punctuators and
							// end-of-string tokens.
							for (value = "@", Index++; Index < length;) {
								charCode = source.charCodeAt(Index);
								if (charCode < 32) {
									// Unescaped ASCII control characters (those
									// with a code unit
									// less than the space character) are not
									// permitted.
									abort();
								} else if (charCode == 92) {
									// A reverse solidus (`\`) marks the
									// beginning of an escaped
									// control character (including `"`, `\`,
									// and `/`) or Unicode
									// escape sequence.
									charCode = source.charCodeAt(++Index);
									switch (charCode) {
										case 92 :
										case 34 :
										case 47 :
										case 98 :
										case 116 :
										case 110 :
										case 102 :
										case 114 :
											// Revive escaped control
											// characters.
											value += Unescapes[charCode];
											Index++;
											break;
										case 117 :
											// `\u` marks the beginning of a
											// Unicode escape sequence.
// Advance to the first character and validate the
											// four-digit code point.
											begin = ++Index;
											for (position = Index + 4; Index < position; Index++) {
												charCode = source
														.charCodeAt(Index);
												// A valid sequence comprises
												// four hexdigits (case-
												// insensitive) that form a
												// single hexadecimal value.
												if (!(charCode >= 48
														&& charCode <= 57
														|| charCode >= 97
														&& charCode <= 102 || charCode >= 65
														&& charCode <= 70)) {
													// Invalid Unicode escape
													// sequence.
													abort();
												}
											}
											// Revive the escaped character.
											value += fromCharCode("0x"
													+ source
															.slice(begin, Index));
											break;
										default :
											// Invalid escape sequence.
											abort();
									}
								} else {
									if (charCode == 34) {
										// An unescaped double-quote character
										// marks the end of the
										// string.
										break;
									}
									charCode = source.charCodeAt(Index);
									begin = Index;
									// Optimize for the common case where a
									// string is valid.
									while (charCode >= 32 && charCode != 92
											&& charCode != 34) {
										charCode = source.charCodeAt(++Index);
									}
									// Append the string as-is.
									value += source.slice(begin, Index);
								}
							}
							if (source.charCodeAt(Index) == 34) {
								// Advance to the next character and return the
								// revived string.
								Index++;
								return value;
							}
							// Unterminated string.
							abort();
						default :
							// Parse numbers and literals.
							begin = Index;
							// Advance past the negative sign, if one is
							// specified.
							if (charCode == 45) {
								isSigned = true;
								charCode = source.charCodeAt(++Index);
							}
							// Parse an integer or floating-point value.
							if (charCode >= 48 && charCode <= 57) {
								// Leading zeroes are interpreted as octal
								// literals.
								if (charCode == 48
										&& ((charCode = source.charCodeAt(Index
												+ 1)), charCode >= 48
												&& charCode <= 57)) {
									// Illegal octal literal.
									abort();
								}
								isSigned = false;
								// Parse the integer component.
								for (; Index < length
										&& ((charCode = source
												.charCodeAt(Index)), charCode >= 48
												&& charCode <= 57); Index++);
								// Floats cannot contain a leading decimal
								// point; however, this
								// case is already accounted for by the parser.
								if (source.charCodeAt(Index) == 46) {
									position = ++Index;
									// Parse the decimal component.
									for (; position < length
											&& ((charCode = source
													.charCodeAt(position)), charCode >= 48
													&& charCode <= 57); position++);
									if (position == Index) {
										// Illegal trailing decimal.
										abort();
									}
									Index = position;
								}
								// Parse exponents. The `e` denoting the
								// exponent is
								// case-insensitive.
								charCode = source.charCodeAt(Index);
								if (charCode == 101 || charCode == 69) {
									charCode = source.charCodeAt(++Index);
									// Skip past the sign following the
									// exponent, if one is
									// specified.
									if (charCode == 43 || charCode == 45) {
										Index++;
									}
									// Parse the exponential component.
									for (position = Index; position < length
											&& ((charCode = source
													.charCodeAt(position)), charCode >= 48
													&& charCode <= 57); position++);
									if (position == Index) {
										// Illegal empty exponent.
										abort();
									}
									Index = position;
								}
								// Coerce the parsed value to a JavaScript
								// number.
								return +source.slice(begin, Index);
							}
							// A negative sign may only precede numbers.
							if (isSigned) {
								abort();
							}
							// `true`, `false`, and `null` literals.
							if (source.slice(Index, Index + 4) == "true") {
								Index += 4;
								return true;
							} else if (source.slice(Index, Index + 5) == "false") {
								Index += 5;
								return false;
							} else if (source.slice(Index, Index + 4) == "null") {
								Index += 4;
								return null;
							}
							// Unrecognized token.
							abort();
					}
				}
				// Return the sentinel `$` character if the parser has reached
				// the end
				// of the source string.
				return "$";
			};

			// Internal: Parses a JSON `value` token.
			var get = function(value) {
				var results, hasMembers;
				if (value == "$") {
					// Unexpected end of input.
					abort();
				}
				if (typeof value == "string") {
					if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") {
						// Remove the sentinel `@` character.
						return value.slice(1);
					}
					// Parse object and array literals.
					if (value == "[") {
						// Parses a JSON array, returning a new JavaScript
						// array.
						results = [];
						for (;; hasMembers || (hasMembers = true)) {
							value = lex();
							// A closing square bracket marks the end of the
							// array literal.
							if (value == "]") {
								break;
							}
							// If the array literal contains elements, the
							// current token
							// should be a comma separating the previous element
							// from the
							// next.
							if (hasMembers) {
								if (value == ",") {
									value = lex();
									if (value == "]") {
										// Unexpected trailing `,` in array
										// literal.
										abort();
									}
								} else {
									// A `,` must separate each array element.
									abort();
								}
							}
							// Elisions and leading commas are not permitted.
							if (value == ",") {
								abort();
							}
							results.push(get(value));
						}
						return results;
					} else if (value == "{") {
						// Parses a JSON object, returning a new JavaScript
						// object.
						results = {};
						for (;; hasMembers || (hasMembers = true)) {
							value = lex();
							// A closing curly brace marks the end of the object
							// literal.
							if (value == "}") {
								break;
							}
							// If the object literal contains members, the
							// current token
							// should be a comma separator.
							if (hasMembers) {
								if (value == ",") {
									value = lex();
									if (value == "}") {
										// Unexpected trailing `,` in object
										// literal.
										abort();
									}
								} else {
									// A `,` must separate each object member.
									abort();
								}
							}
							// Leading commas are not permitted, object property
							// names must be
							// double-quoted strings, and a `:` must separate
							// each property
							// name and value.
							if (value == ","
									|| typeof value != "string"
									|| (charIndexBuggy
											? value.charAt(0)
											: value[0]) != "@" || lex() != ":") {
								abort();
							}
							results[value.slice(1)] = get(lex());
						}
						return results;
					}
					// Unexpected token encountered.
					abort();
				}
				return value;
			};

			// Internal: Updates a traversed object member.
			var update = function(source, property, callback) {
				var element = walk(source, property, callback);
				if (element === undef) {
					delete source[property];
				} else {
					source[property] = element;
				}
			};

			// Internal: Recursively traverses a parsed JSON object, invoking
			// the
			// `callback` function for each value. This is an implementation of
			// the
			// `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2.
			var walk = function(source, property, callback) {
				var value = source[property], length;
				if (typeof value == "object" && value) {
					// `forEach` can't be used to traverse an array in Opera <=
					// 8.54
					// because its `Object#hasOwnProperty` implementation
					// returns `false`
					// for array indices (e.g., `![1, 2,
					// 3].hasOwnProperty("0")`).
					if (getClass.call(value) == arrayClass) {
						for (length = value.length; length--;) {
							update(value, length, callback);
						}
					} else {
						forEach(value, function(property) {
									update(value, property, callback);
								});
					}
				}
				return callback.call(source, property, value);
			};

			// Public: `JSON.parse`. See ES 5.1 section 15.12.2.
			JSON3.parse = function(source, callback) {
				var result, value;
				Index = 0;
				Source = "" + source;
				result = get(lex());
				// If a JSON string contains multiple tokens, it is invalid.
				if (lex() != "$") {
					abort();
				}
				// Reset the parser state.
				Index = Source = null;
				return callback && getClass.call(callback) == functionClass
						? walk((value = {}, value[""] = result, value), "",
								callback)
						: result;
			};
		}
	}

	// Export for asynchronous module loaders.
	if (isLoader) {
		define(function() {
					return JSON3;
				});
	}
}(this));
